package org.luckyjourney.util;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import org.luckyjourney.constant.RedisConstant;
import org.luckyjourney.entity.user.User;
import org.luckyjourney.service.user.UserService;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RCascadeType;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.time.Duration;
import java.util.*;

@Component
public class BloomFilterUtil {

    @Resource
    private RedissonClient redissonClient;

    private static final Map<Long, RBloomFilter> browsingHistory = new HashMap<>();

    private static  int MAX_CAPACITY;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 创建布隆过滤器
     * 什么时候调用：1. 项目启动时导入所有用户的历史记录  -> 采用
     *            2. 用户登录时导入，退出时销毁 未实现判断用户在线功能
     *            3. 用户调用登录接口时创建布隆过滤器
     * @param filterName         过滤器名称
     * @param expectedInsertions 预测插入数量
     * @param falsePositiveRate  误判率
     */
    public <T> RBloomFilter<T> createAndInit(Long userId, String filterName, long expectedInsertions, double falsePositiveRate) {
        RBloomFilter<T> bloomFilter = redissonClient.getBloomFilter(filterName + ":" + userId);
        bloomFilter.tryInit(expectedInsertions, falsePositiveRate);
        browsingHistory.put(userId, bloomFilter);
        initFilter(userId);
        return bloomFilter;
    }


    // videos存储的是redis返回的Integer类型，不能用流式方法遍历
    public void initFilter(Long userId) {
        RBloomFilter bloomFilter = browsingHistory.get(userId);
        if(bloomFilter == null) return;
        Set<Long> videos = getHistoryByUser(userId);
        if (videos != null) {
            Iterator<Long> it = videos.iterator();
            while(it.hasNext()){
                bloomFilter.add(it.next());
            }
        }
    }


    public boolean contains(Long userId, Long videoId){
        RBloomFilter filter = browsingHistory.get(userId);
        if(filter == null || videoId == null) return false;
        return filter.contains(videoId);
    }


    public boolean add(Long userId, Long videoId){
        RBloomFilter filter = browsingHistory.get(userId);
        if(filter == null || videoId == null) return false;
        // 超出预期容量时布隆过滤器误判率大大提高
        if(filter.count() >= MAX_CAPACITY) {
            return false;
        }
        return filter.add(videoId);
    }


    /**
     * 获取用户浏览记录
     * @param userId 用户id
     * @return 视频id集合
     */
    private Set<Long> getHistoryByUser(Long userId) {
        String key = RedisConstant.HISTORY_VIDEO + userId;
        Set videoIds = redisTemplate.opsForSet().members(key);
        return videoIds;
    }

    /**
     * 创建所有用户的历史记录过滤器
     * @param users 用户集合
     * @param filterName 前缀过滤器名
     * @param expectedInsertions 期望插入过滤器的数据量
     * @param falsePositiveRate 误差精度
     */
    public void creatAll(List<User> users, String filterName, long expectedInsertions, double falsePositiveRate) {
        MAX_CAPACITY = (int) expectedInsertions;
        for (User user : users) {
            Long id = user.getId();
            createAndInit(id, filterName, expectedInsertions, falsePositiveRate);
        }
    }
}
